package com.luty.rpc.server;

import com.luty.rpc.bean.RpcRequest;
import com.luty.rpc.bean.RpcResponse;
import com.luty.rpc.util.StringUtil;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;

/**
 * Created by liuyunxin on 2017/7/2.
 */
public class RpcServerHandler extends SimpleChannelInboundHandler<RpcRequest>{

    private static final Logger LOGGER = LoggerFactory.getLogger(RpcServerHandler.class);
    private final  Map<String, Object> handlerMap;

    public RpcServerHandler(Map<String, Object> handlerMap){
        this.handlerMap = handlerMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequest rpcRequest) throws Exception {
        RpcResponse response = new RpcResponse();

        response.setRequestId(rpcRequest.getRequestId());
        try{
            Object result = handle(rpcRequest);
            response.setResult(result);
        }catch (InvocationTargetException e){
            LOGGER.error("handle result failure", e);
            response.setException(e);
        }

        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

    private Object handle(RpcRequest request) throws InvocationTargetException {
        String serviceName = request.getInterfaceName();
        String serviceVersion = request.getServiceVersion();
        if(!StringUtil.isEmpty(serviceVersion)){
            serviceName += serviceVersion;
        }

        Object serviceBean = handlerMap.get(serviceName);
        if (serviceBean == null) {
            throw new RuntimeException(String.format("can not find service bean by key: %s", serviceName));
        }
        Class<?> serviceClass = serviceBean.getClass();
        String methodName = request.getMethodName();

        Class[] parameterType = request.getParameterTypes();
        Object[] parameters = request.getParameters();


        FastClass fastClass = FastClass.create(serviceClass);
        FastMethod fastMethod = fastClass.getMethod(methodName,parameterType);

        return fastMethod.invoke(serviceBean,parameters);
    }
}
